#include <retro.h>
#include "retro.creator.h"

using namespace Retro::Creator::Toolbox;
using namespace Retro::Creator::GUI;
using namespace SPLib::Geom;

#define LAYOUT_MARGIN 4

#define NUMERIC_EDIT_STYLE \
  WS_CHILD | WS_TABSTOP | ES_NUMBER | ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN
#define NUMERIC_EDIT_EXSTYLE \
  WS_EX_LEFT | WS_EX_CLIENTEDGE | WS_EX_CONTEXTHELP

#define NUMERIC_UPDOWN_STYLE \
  WS_CHILD | UDS_ARROWKEYS | UDS_HOTTRACK | UDS_SETBUDDYINT
#define NUMERIC_UPDOWN_EXSTYLE \
  WS_EX_LEFT | WS_EX_LTRREADING

enum SelectorItem
{
  SelectorErase = 0x0001,
  SelectorTool,
  SelectorSpriteType,
  SelectorTileSelector,
  SelectorToolbar,
  SelectorColorbar,
  SelectorTexture,
  SelectorWidth,
  SelectorHeight,
  SelectorColorModeMenu,
  SelectorColor,
};

static TCHAR gText[100];

Selector::Selector() :
  mFont(CreateFont(
  16, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
  OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,
  VARIABLE_PITCH, _T("Arial"))
  ),
  mTextFont(GetDC(NULL), mFont),
  mHeadingFont(_T("Microsoft Sans Serif"), 10, Gdip::FontStyleBold)
{
  mLayout   = NULL;
  resource  = NULL;
  mNoNotify = FALSE;

  for (UINT i = 0; i < ARRAYSIZE(mColors); ++i)
    mColors[i].value = 0xFFFFFFFF;

  mColorMode = ColorAll;
}

VOID  Selector::NumericItem::create(
  Selector& iParent,
  INT       iID,
  PCTSTR    iText,
  INT       iMin,
  INT       iMax,
  INT       iIncrement
  )
{
  label.create(iParent);
  label.setText(iText);
  label.setFont(&iParent.mTextFont);

  edit.create(iParent.getHandle(), WC_EDIT, _T(""),
    NUMERIC_EDIT_STYLE, NUMERIC_EDIT_EXSTYLE);

  edit.setFont(iParent.mFont);
  edit.setID(iID);

  scroll.create(iParent.getHandle(), UPDOWN_CLASS, _T(""),
    NUMERIC_UPDOWN_STYLE, NUMERIC_UPDOWN_EXSTYLE);

  UDACCEL wIncrements[] =
  {
    { 0, iIncrement      },
    { 1, iIncrement * 2  },
    { 2, iIncrement * 10 }
  };

  scroll.send(UDM_SETRANGE32, iMin, iMax);
  scroll.send(UDM_SETBUDDY, (WPARAM)(HWND)edit, 0);
  scroll.send(UDM_SETACCEL, ARRAYSIZE(wIncrements), (LPARAM)wIncrements);
}

VOID  Selector::NumericItem::addToLayout(
  LayoutElement* iLayout,
  INT iTextWidth,
  INT iEditWidth
  )
{
  iLayout->margins.setVert(LAYOUT_MARGIN);
  iLayout->addLeft(iTextWidth, label)->margins.left = LAYOUT_MARGIN;
  iLayout->addLeft(iEditWidth, edit);
  iLayout->addLeft(20, scroll);
}

VOID  Selector::onCreate(Event::WndCreateEvent& iEvent)
{
  mLayout = getHandle();

  mToolbar.create       (*this);
  mTileSelector.create  (*this);
  mWidth.create         (*this, SelectorWidth,      _T("Width"),  1, 1000, 10);
  mSliderWidth.create   (*this);
  mHeight.create        (*this, SelectorHeight,     _T("Height"), 1, 1000, 10);
  mSliderHeight.create  (*this);
  mColorbar.create      (*this);
  mColorPicker.create   (*this);

  mToolbar.setID(SelectorToolbar);
  mToolbar.addStyle(WS_TABSTOP);

  mTileSelector.setID(SelectorTileSelector);
  mTileSelector.addStyle(WS_TABSTOP);

  mMenuTexture.createPopup();

  mMenuTool.createPopup();
  mMenuTool.append(TileToolSelect,    _T("Tiles"));
  mMenuTool.append(TileToolDirection, _T("Direction"));
  mMenuTool.append(TileToolFlags,     _T("Flags"));

  mMenuSprite.createPopup();
  mMenuSprite.append(Data::SpriteTexture + 1,  _T("Texture"));
  mMenuSprite.append(Data::SpriteRect + 1,     _T("Rectangle"));

  mMenuColor.createPopup();
  mMenuColor.append(ColorAll + 1,         _T("All"));
  mMenuColor.appendSeparator();
  mMenuColor.append(ColorTopLeft + 1,     _T("Top Left"));
  mMenuColor.append(ColorTopRight + 1,    _T("Top Right"));
  mMenuColor.append(ColorBottomLeft + 1,  _T("Bottom Left"));
  mMenuColor.append(ColorBottomRight + 1, _T("Bottom Right"));
  mMenuColor.appendSeparator();
  mMenuColor.append(ColorLeft + 1,        _T("Left"));
  mMenuColor.append(ColorRight + 1,       _T("Right"));
  mMenuColor.append(ColorTop + 1,         _T("Top"));
  mMenuColor.append(ColorBottom + 1,      _T("Bottom"));

  // create color menu
  {
    ToolItem items[] = {
      { 0,                      _T("Color"),  ToolItemLabel,  NULL, 45    },
      { SelectorColorModeMenu,  _T(""),       ToolItemMenu,   mMenuColor  },
    };

    mColorbar.addItems(items, sizeof(items) / sizeof(ToolItem));
    mColorbar.setID(SelectorColorbar);
    mColorbar.addStyle(WS_TABSTOP);
  }

  mSeparator1.create(*this);
  mSeparator2.create(*this);

  mSizeLabel.create(*this);
  mSizeLabel.setText(_T("Size"));
  mSizeLabel.setFont(&mHeadingFont);
  mSizeLabel.setForeColor(Control::getTheme().textDisabled);

  mSliderWidth.setID(SelectorWidth);
  mSliderWidth.addStyle(WS_TABSTOP);
  mSliderWidth.setInterval(1, 1000);
  mSliderWidth.setIncrement(25);
  mSliderWidth.setValue(100);

  mSliderHeight.setID(SelectorHeight);
  mSliderHeight.addStyle(WS_TABSTOP);
  mSliderHeight.setInterval(1, 1000);
  mSliderHeight.setIncrement(25);
  mSliderHeight.setValue(100);

  mColorPicker.setID(SelectorColor);
  //mColorPicker.addStyle(WS_TABSTOP);
}

VOID  Selector::onDestroy()
{
  mMenuTexture.destroy();
  mMenuSprite.destroy();
  mMenuTool.destroy();
  mLayout.destroy();

  DeleteObject(mFont);
}

VOID  Selector::onSize(Event::SizeEvent& iEvent)
{
  mLayout.doLayout();

  if (!resource)
    invalidate();
}

VOID  Selector::onCommand(Event::CommandEvent& iEvent)
{
  if (mNoNotify) return;

  switch (iEvent.id)
  {
  case SelectorWidth:
    if (iEvent.code == EN_CHANGE)
    {
      mSliderWidth.setValue((LONG)
        mWidth.scroll.send(UDM_GETPOS32, NULL, NULL));
    }
  case SelectorHeight:
    if (iEvent.code == EN_CHANGE)
    {
      mSliderHeight.setValue((LONG)
        mHeight.scroll.send(UDM_GETPOS32, NULL, NULL));
    }
    break;
  }
}

VOID  Selector::onNotify(Event::NotifyEvent& iEvent)
{
  if (mNoNotify) return;

  switch (iEvent.data->idFrom)
  {
  case SelectorToolbar:
    {
      ToolBarNotify* data = (ToolBarNotify*)iEvent.data;

      switch (data->itemID)
      {
      case SelectorErase:
        mTileSelector.setErase(TRUE);
        break;
      case SelectorTool:
        setTileTool((TileTool)data->value);
        break;
      case SelectorSpriteType:
        setSpriteType((Data::SpriteType)(data->value - 1));
        break;
      case SelectorTexture:
        setTexture((Data::Texture*)mMenuTexture.getItemData(data->value));
        break;
      }
    }
    break;
  case SelectorColorbar:
    {
      ToolBarNotify* data = (ToolBarNotify*)iEvent.data;

      switch (data->itemID)
      {
      case SelectorColorModeMenu:
        setColorMode(SelectorColorMode(data->value - 1));
        break;
      }
    }
    break;
  case SelectorTileSelector:
    switch (iEvent.data->code)
    {
    case TileNotifySelection:
      sendNotify(SelectorNotifySelection);
      break;
    case TileNotifyEdit:
      sendNotify(SelectorNotifyEdit);
      break;
    case TileNotifyErase:
      sendNotify(SelectorNotifyErase);
      break;
    }
    break;
  case SelectorWidth:
  case SelectorHeight:
    sendNotify(SelectorNotifySelection);

    mWidth.scroll.send(UDM_SETPOS32, 0, mSliderWidth.getValue());
    mHeight.scroll.send(UDM_SETPOS32, 0, mSliderHeight.getValue());
    break;
  case SelectorColor:
    updateColor();
    break;
  }
}

VOID  Selector::onFocus(Event::FocusEvent& iEvent)
{
  if (iEvent.focused)
    mToolbar.focus();
}

VOID  Selector::onEraseBackground(Event::EraseBackgroundEvent& iEvent)
{
  *iEvent.handled = TRUE;
}

VOID  Selector::onPaint()
{
  Geom::Rect client = getClient();
  PAINTSTRUCT paint;

  {
    Gdip::Graphics g(beginPaint(&paint));

    g.Clear(Control::getTheme().containerBg);

    if (!resource || (resource->getType() != Data::ResourceGridMap &&
      resource->getType() != Data::ResourceSpriteMap))
    {
      Gdip::StringFormat format;

      format.SetAlignment(Gdip::StringAlignmentCenter);
      format.SetLineAlignment(Gdip::StringAlignmentCenter);

      g.DrawString(_T("No Map Opened"), -1,
        &Gdip::Font(_T("Arial"), 12, Gdip::FontStyleBold),
        Gdip::RectF(0, 0,
        (REAL)client.getWidth(),
        (REAL)client.getHeight()),
        &format,
        &Gdip::SolidBrush(Control::getTheme().textDisabled));
    }
  }

  endPaint(&paint);
}

VOID  Selector::initGridBar()
{
  // toolbar items
  ToolItem items[] = {
    { 0,              _T("Tools"),   ToolItemLabel                   },
    { SelectorErase,  _T("Erasor"),  ToolItemButton                  },
    { 0,              _T("View"),    ToolItemLabel                   },
    { SelectorTool,   _T(""),        ToolItemMenu,   mMenuTool, 100  },
  };

  // add toolbar items
  mToolbar.addItems(items, sizeof(items) / sizeof(ToolItem));
}

VOID  Selector::setResource(Data::Resource* res)
{
  mLayout.clear();
  mToolbar.clear();
  mTileSelector.setTexture(NULL);

  mContent        = NULL;
  mLayoutToolbar  = NULL;

  if ((resource = res))
  {
    switch (res->getType())
    {
    case Data::ResourceGridMap:
      initGridBar();

      mLayoutToolbar = mLayout.addTop(TOOLBAR_HEIGHT, mToolbar);
      mLayoutToolbar->margins.setAll(LAYOUT_MARGIN);
      mLayout.addFill(mTileSelector);

      mTileSelector.setTexture((Data::Texture*)
        Frame::get()->getProject().findResource(Data::ResourceTexture,
        ((Data::GridMap*)res)->getTilesetID()));
      break;
    case Data::ResourceSpriteMap:
      mLayoutToolbar = mLayout.addTop(TOOLBAR_HEIGHT, mToolbar);
      mLayoutToolbar->margins.setAll(LAYOUT_MARGIN);
      mContent = mLayout.addFill();

      loadTextures();
      setSpriteType(Data::SpriteTexture);
      break;
    }
  }

  setTileTool(TileToolSelect);
  invalidate();

  mLayout.doLayout();
}

VOID  Selector::loadTextures()
{
  const Generic::Vector<Data::Resource*>& wResources =
    Frame::get()->getProject().getResources();

  mMenuTexture.clear();

  Data::Texture* wFirstTexture = NULL;

  for (UINT i = 0; i < wResources.getLength(); ++i)
  {
    if (wResources[i]->getType() == Data::ResourceTexture)
    {
      _stprintf(gText, _T("%.4d - %s"),
        wResources[i]->getID(),
        wResources[i]->getName());

      mMenuTexture.append(wResources[i]->getID(), gText);
      mMenuTexture.setItemData(wResources[i]->getID(), wResources[i]);

      if (!wFirstTexture)
        wFirstTexture = (Data::Texture*)wResources[i];
    }
  }

  if (!mTileSelector.getTexture())
    setTexture(wFirstTexture);
}

VOID  Selector::setTexture(Data::Texture* iValue)
{
  if (resource->getType() != Data::ResourceSpriteMap)
    return;

  if (mTileSelector.getTexture())
  {
    mMenuTexture.setItemChecked(
      mTileSelector.getTexture()->getID(),
      MenuFlagUnchecked);
  }

  if (iValue)
  {
    _stprintf(gText, _T("%.4d - %s"), iValue->getID(), iValue->getName());
    mMenuTexture.setItemChecked(iValue->getID(), MenuFlagChecked);
  }
  else
  {
    gText[0] = '\0';
  }

  mToolbar.setItemText(gText, SelectorTexture);
  mTileSelector.setTexture(iValue);
  sendNotify(SelectorNotifyTexture);
}

VOID  Selector::setTileTool(TileTool iValue)
{
  mTileSelector.setTool(iValue);

  Menu_GetItemText(mMenuTool, iValue, gText);
  mToolbar.setItemText(gText, SelectorTool);
}

VOID  Selector::setSpriteType(Data::SpriteType iValue)
{
  if (!mContent) return;

  LayoutElement* wLayout;

  Menu_GetItemText(mMenuSprite, (iValue + 1), gText);

  mContent->clear();

  mToolbar.clear();
  mToolbar.addItem(0, _T("Type"), ToolItemLabel, NULL, 45);
  mToolbar.addItem(SelectorSpriteType, NULL, ToolItemMenu, mMenuSprite);
  mToolbar.setItemText(gText, SelectorSpriteType);

  mLayoutToolbar->size.cy = TOOLBAR_HEIGHT;

  switch (mSpriteType = iValue)
  {
  case Data::SpriteTexture:
    mToolbar.addItem(0, NULL, ToolItemBreak);
    mToolbar.addItem(0, _T("Value"), ToolItemLabel, NULL, 45);
    mToolbar.addItem(SelectorTexture, NULL, ToolItemMenu, mMenuTexture, 200);

    mLayoutToolbar->size.cy = TOOLBAR_HEIGHT * 2 + 6;

    mContent->margins.setAll(0);
    mContent->addFill(mTileSelector);

    setTexture(mTileSelector.getTexture());
    break;
  case Data::SpriteRect:
    mContent->margins.setHoriz(LAYOUT_MARGIN);

    // sprite size
    mContent->addTop(5, mSeparator1)->margins.set(
      0, 0, LAYOUT_MARGIN * 2, LAYOUT_MARGIN);
    mContent->addTop(25, mSizeLabel)->margins.setVert(LAYOUT_MARGIN);

    // sprite width
    wLayout = mContent->addTop(23);
    mWidth.addToLayout(wLayout, 50, 50);
    wLayout->addFill(mSliderWidth)->margins.setHoriz(LAYOUT_MARGIN);

    // sprite height
    wLayout = mContent->addTop(23);
    mHeight.addToLayout(wLayout, 50, 50);
    wLayout->addFill(mSliderHeight)->margins.setHoriz(LAYOUT_MARGIN);

    // sprite color
    mContent->addTop(5, mSeparator2)->margins.set(
      0, 0, LAYOUT_MARGIN * 2, LAYOUT_MARGIN);
    //mContent->addTop(25, mColorLabel)->margins.setVert(LAYOUT_MARGIN);

    mContent->addTop(TOOLBAR_HEIGHT, mColorbar);

    // sprite color picker
    wLayout = mContent->addTop(125, mColorPicker);
    wLayout->margins.setVert(LAYOUT_MARGIN);
    break;
  }

  mLayout.doLayout();
  setColorMode(ColorAll);
  sendNotify(SelectorNotifySpriteType);
}

VOID  Selector::setColorMode(SelectorColorMode iValue)
{
  TCHAR wName[100];

  mMenuColor.getItemText(iValue + 1, wName, ARRAYSIZE(wName));
  mColorbar.setItemText(wName, SelectorColorModeMenu);

  mColorMode = iValue;

  RGBColor wColor;

  switch (iValue)
  {
  case ColorLeft:
  case ColorTop:
  case ColorAll:
    wColor = mColors[ColorTopLeft];
    break;
  case ColorRight:
    wColor = mColors[ColorTopRight];
    break;
  case ColorBottom:
    wColor = mColors[ColorBottomLeft];
    break;
  default:
    wColor = mColors[iValue];
    break;
  }

  mColorPicker.setColor(wColor);
}

VOID  Selector::updateColor()
{
  RGBColor wRGB = mColorPicker.getColor();

  switch (mColorMode)
  {
  case ColorLeft:
    mColors[ColorTopLeft]    = mColors[ColorBottomLeft]  = wRGB;
    break;
  case ColorRight:
    mColors[ColorTopRight]   = mColors[ColorBottomRight] = wRGB;
    break;
  case ColorTop:
    mColors[ColorTopLeft]    = mColors[ColorTopRight]    = wRGB;
    break;
  case ColorBottom:
    mColors[ColorBottomLeft] = mColors[ColorBottomRight] = wRGB;
    break;
  case ColorAll:
    for (UINT i = 0; i < ARRAYSIZE(mColors); ++i)
      mColors[i].value = wRGB;
    break;
  default:
    mColors[mColorMode] = wRGB;
    break;
  }

  sendNotify(SelectorNotifySelection);
}
